#include "TagFileBuffer.h"
#include "readtags.h"
#include <algorithm>
using namespace std;

TagFileBuffer::TagFileBuffer() {
}

TagFileBuffer::~TagFileBuffer() {
	
}

namespace {
	bool str_cmp(const string str1, const string str2) {
		int i = 0;
		char c1, c2;
		while (i < str1.size() && i < str2.size()) {
			c1 = str1[i];
			c2 = str2[i];
			if (c1 <='z' && c1>='a') {c1 -= 32;}
			if (c2 <='z' && c2>='a') {c2 -= 32;}
			if (c1 != c2) {
				return c1 < c2;
			} else {
				++i;
			}
		}
		return i != str2.size();
	}
}

void TagFileBuffer::ReadTags( const char * filename ) {
	string res;
	tagFileInfo info;
	tagFile* file = tagsOpen(filename, &info);
	if (!info.status.opened) {
		file = 0;
		goto endfunc;
	}

	tagEntry entry;
	if (tagsFirst(file, &entry) == TagFailure) {
		goto endfunc;
	}

	unsigned i;
	do {
		names.push_back(entry.name);
		for (i = 0; i < entry.fields.count; ++i) {
			if (entry.fields.list[i].value) {
				string type = entry.fields.list[i].value;
				int j, m = -1;
				for (j = 0; j < (int)type.size() - 1; ++j) {
					if (type[j] == ':' && type[j+1] == ':') {
						m = j;
					}
				}
				if (m > -1) {
					type.erase(type.begin(), type.begin() + m + 2);
				}
				table[type].push_back(entry.name);
				break;
			}
		}
	} while (tagsNext(file, &entry));

	sort(names.begin(), names.end()/*, str_cmp*/);
	names.erase(unique(names.begin(), names.end()), names.end());

endfunc:
	if (file) {
		tagsClose(file);
	}
}


void TagFileBuffer::GetNearestTags( const char* prefix, std::vector<std::string> *wordList ) {
	string pre(prefix);
	if (pre.size() < 2) {
		return ;
	}
	vector<string>::iterator iter_begin = lower_bound(names.begin(), names.end() ,pre/*, str_cmp*/);
	++pre[pre.size() - 1];
	vector<string>::iterator iter_end = lower_bound(iter_begin, names.end(), pre/*, str_cmp*/);
	while (iter_begin < iter_end) {
		wordList->push_back(*iter_begin++);
	}
	vector<string> &nameList = *wordList;
	sort(nameList.begin(), nameList.end());
	nameList.erase(unique(nameList.begin(), nameList.end()), nameList.end());
}

void TagFileBuffer::GetFieldTags( std::string field, std::vector<std::string> *wordList ) {
	map<string, vector<string>>::iterator iter = table.find(field);
	if (iter == table.end()) {
		return ;
	}
	for (vector<string>::iterator it = iter->second.begin(); it != iter->second.end(); ++it) {
		wordList->push_back(*it);
	}
	vector<string> &nameList = *wordList;
	sort(nameList.begin(), nameList.end());
	nameList.erase(unique(nameList.begin(), nameList.end()), nameList.end());
}
